#pragma once

#include <iostream>
#include <vector>
#include <cassert>
#include <semaphore.h>

// 单生产，单消费——生产者和消费者互斥
// template<class T>
// class RingQueue
// {
//     const static size_t g_cap = 5;
// private:
//     void P(sem_t& sem)
//     {
//         int n = sem_wait(&sem);
//         assert(n == 0);// 建议使用if
//         (void)n;
//     }
//     void V(sem_t& sem)
//     {
//         int n = sem_post(&sem);
//         assert(n == 0);// 建议使用if
//         (void)n;
//     }
// public:
//     RingQueue(const size_t cap = g_cap): _queue(cap), _cap(cap), _producer_step(0), _consumer_step(0)
//     {
//         int n = sem_init(&_sapce_sem, 0, _cap);
//         assert(n == 0);
//         n = sem_init(&_data_sem, 0, 0);
//         assert(n == 0);
//         (void)n;
//     }

//     void push(const T& in)
//     {
//         // 生产者
//         P(_sapce_sem);
//         _queue[_producer_step++] = in;
//         _producer_step %= _cap;
//         V(_data_sem);
//     }
//     void pop(T* out)
//     {
//         // 消费者
//         P(_data_sem);
//         *out = _queue[_consumer_step++];
//         _consumer_step %= _cap;
//         V(_sapce_sem);
//     }
//     ~RingQueue()
//     {
//         _queue.clear();
//         sem_destroy(&_sapce_sem);
//         sem_destroy(&_data_sem);
//     }
// private:
//     std::vector<T> _queue;// 环形队列
//     size_t _cap;// 队列容量
//     sem_t _sapce_sem;// 生产者关注 空间资源
//     sem_t _data_sem;// 消费者关注 数据资源
//     int _producer_step;
//     int _consumer_step;
// };

// 多生产，多消费——添加生产者互斥和消费者互斥 -> 加锁
#include <pthread.h>

template<class T>
class RingQueue
{
    const static size_t g_cap = 5;
private:
    void P(sem_t& sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0);// 建议使用if
        (void)n;
    }
    void V(sem_t& sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);// 建议使用if
        (void)n;
    }
public:
    RingQueue(const size_t cap = g_cap): _queue(cap), _cap(cap), _producer_step(0), _consumer_step(0)
    {
        int n = sem_init(&_sapce_sem, 0, _cap);
        assert(n == 0);
        n = sem_init(&_data_sem, 0, 0);
        assert(n == 0);
        (void)n;

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);
    }

    void push(const T& in)
    {
        // 生产者
        P(_sapce_sem);
        pthread_mutex_lock(&_pmutex);
        _queue[_producer_step++] = in;
        _producer_step %= _cap;
        pthread_mutex_unlock(&_pmutex);
        V(_data_sem);
    }
    void pop(T* out)
    {
        // 消费者
        P(_data_sem);
        pthread_mutex_lock(&_cmutex);
        *out = _queue[_consumer_step++];
        _consumer_step %= _cap;
        pthread_mutex_unlock(&_cmutex);
        V(_sapce_sem);
    }
    ~RingQueue()
    {
        _queue.clear();
        sem_destroy(&_sapce_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }
private:
    std::vector<T> _queue;// 环形队列
    size_t _cap;// 队列容量
    sem_t _sapce_sem;// 生产者关注 空间资源
    sem_t _data_sem;// 消费者关注 数据资源
    int _producer_step;
    int _consumer_step;

    // 多生产多消费
    pthread_mutex_t _pmutex;// 生产者锁
    pthread_mutex_t _cmutex;// 消费者锁
};